package com.acooly.module.openapi.client.api.transport;

import com.acooly.core.utils.Collections3;
import com.acooly.core.utils.net.HttpResult;
import com.acooly.module.openapi.client.api.exception.ApiClientNetworkException;
import com.acooly.module.openapi.client.api.exception.ApiClientSocketTimeoutException;
import com.acooly.module.openapi.client.api.exception.ApiServerException;
import com.github.kevinsawicki.http.HttpRequest;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import java.net.SocketTimeoutException;
import java.util.List;
import java.util.Map;

/**
 * 简单通讯组件
 *
 * @author zhangpu
 */
public class HttpSimpleTransport implements Transport {

    protected static Logger logger = LoggerFactory.getLogger(HttpSimpleTransport.class);
    private String gateway;
    private int readTimeout = 60000;
    private int connTimeout = 20000;
    private String contentType = HttpRequest.CONTENT_TYPE_FORM;
    private String charset = "utf-8";

    @Override
    public HttpResult request(String message) {
        return request(message, this.gateway);
    }

    @Override
    public HttpResult request(String message, String url, Map<String, String> headers) {
        return doRequest(url, message, headers);
    }

    @Override
    public HttpResult request(String message, String url) {
        return request(message, url, null);
    }

    @Override
    public String exchange(String message) {
        return exchange(message, gateway);
    }

    @Override
    public String exchange(String message, String url) {
        return request(message, url).getBody();
    }

    protected HttpResult doRequest(String url, String message, Map<String, String> headers) {
        try {
            HttpRequest httpRequest = HttpRequest.post(url)
                    .headers(headers)
                    .readTimeout(this.readTimeout)
                    .connectTimeout(this.connTimeout)
                    .contentType(this.contentType, this.charset)
                    .send(message);

            if (httpRequest.code() >= 400) {
                throw new ApiServerException("status:" + httpRequest.code() + ", body:" + httpRequest.body());
            }

            HttpResult result = new HttpResult();
            result.setStatus(httpRequest.code());
            result.setBody(httpRequest.body());
            result.setHeaders(Maps.transformEntries(httpRequest.headers(), new Maps.EntryTransformer<String, List<String>, String>() {
                @Override
                public String transformEntry(@Nullable String key, @Nullable List<String> value) {
                    if (Collections3.isEmpty(value)) {
                        return null;
                    }
                    if (value.size() == 0) {
                        return Collections3.getFirst(value);
                    }
                    return Collections3.convertToString(value, ",");
                }
            }));
            return result;
        } catch (ApiServerException ase) {
            throw ase;
        } catch (Exception e) {
            if (e.getCause() != null && e.getCause() instanceof SocketTimeoutException) {
                throw new ApiClientSocketTimeoutException("通讯失败 超时:" + e.getMessage());
            }
            throw new ApiClientNetworkException("通讯失败：" + e.getMessage());
        }

    }

    public String getGateway() {
        return gateway;
    }

    public void setGateway(String gateway) {
        this.gateway = gateway;
    }

    public int getReadTimeout() {
        return readTimeout;
    }

    public void setReadTimeout(int readTimeout) {
        this.readTimeout = readTimeout;
    }

    public int getConnTimeout() {
        return connTimeout;
    }

    public void setConnTimeout(int connTimeout) {
        this.connTimeout = connTimeout;
    }

    public String getContentType() {
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public String getCharset() {
        return charset;
    }

    public void setCharset(String charset) {
        this.charset = charset;
    }
}
